using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Ltf.Remoting.TeamFoundation;
using System.IO;
using System.Runtime.InteropServices;
using Ltf.MonitorLizard.Forms;
using System.Drawing;
using Ltf.Remoting;

namespace Ltf.MonitorLizard.Helpers
{
	public class FileIcons
	{
		[DllImport("Shell32.dll")]
		public static extern IntPtr SHGetFileInfo(
				string pszPath,
				uint dwFileAttributes,
				ref SHFILEINFO psfi,
				uint cbFileInfo,
				uint uFlags
		);

		static Dictionary<LizardOverLayStatus, string> statusIconFiles;
		static Dictionary<LizardOverLayStatus, Bitmap> statusIconBitmaps;

		static FileIcons()
		{
			statusIconFiles = new Dictionary<LizardOverLayStatus, string>();
			statusIconFiles.Add(LizardOverLayStatus.Add, "TortoiseAdded.ico");
			statusIconFiles.Add(LizardOverLayStatus.CheckedInWritable, "TortoiseReadOnly.ico");
			statusIconFiles.Add(LizardOverLayStatus.CheckedOut, "TortoiseInSubVersion.ico");
			statusIconFiles.Add(LizardOverLayStatus.Conflict, "TortoiseConflict.ico");
			statusIconFiles.Add(LizardOverLayStatus.Deleted, "TortoiseDeleted.ico");
			statusIconFiles.Add(LizardOverLayStatus.Different, "TortoiseModified.ico");
			statusIconFiles.Add(LizardOverLayStatus.Locked, "TortoiseLocked.ico");
			statusIconFiles.Add(LizardOverLayStatus.None, "");
			statusIconFiles.Add(LizardOverLayStatus.Other, "");
			statusIconFiles.Add(LizardOverLayStatus.OutOfDate, "TortoiseOutOfDate.ico");
			statusIconFiles.Add(LizardOverLayStatus.ReadOnly, "TortoiseReadOnly.ico");
			statusIconFiles.Add(LizardOverLayStatus.ServerConflict, "TortoiseConflict.ico");
			statusIconFiles.Add(LizardOverLayStatus.Unknown, "LizardQuestion.ico");

			statusIconBitmaps = new Dictionary<LizardOverLayStatus, Bitmap>();

		}

		public ImageList FileIconsImageList;

		public FileIcons(ImageList fileIconImageList)
		{
			if (fileIconImageList == null)
				FileIconsImageList = new ImageList();
			else
				FileIconsImageList = fileIconImageList;

		}

		public string LoadIconForFileExtension(string fileExtension)
		{
			if (FileIconsImageList.Images.ContainsKey(fileExtension))
				return fileExtension;

			string tmpName=Path.Combine( ServerConnections.DefaultConnection.Settings.TempPath,string.Format("temp.{0}",fileExtension));
			bool exists = File.Exists(tmpName);
			if (!exists)
				File.WriteAllText(tmpName,string.Empty);

			FileIconsImageList.Images.Add(fileExtension, GetFileIcon(tmpName));
			return fileExtension;
		}

		public string LoadIconForFileExtensionAndLtfStatus(string fileExtension, LizardOverLayStatus status)
		{
			string key = string.Format("{0}.{1}",fileExtension,status.ToString());
			if (FileIconsImageList.Images.ContainsKey(key))
				return key;

			Image baseImage=null;
			if (FileIconsImageList.Images.ContainsKey(fileExtension))
				baseImage = FileIconsImageList.Images[fileExtension];
			else
			{
				string tmpName = Path.Combine(ServerConnections.DefaultConnection.Settings.TempPath, string.Format("temp.{0}", fileExtension));
				bool exists = File.Exists(tmpName);
				if (!exists)
					File.WriteAllText(tmpName, string.Empty);
				Icon baseIcon = GetFileIcon(tmpName);
				FileIconsImageList.Images.Add(fileExtension, baseIcon);
				baseImage = FileIconsImageList.Images[fileExtension];
			}
			Bitmap fileBitmap = new Bitmap(baseImage);
			Bitmap statusBitmap = null;
			if (statusIconBitmaps.ContainsKey(status))
				statusBitmap = statusIconBitmaps[status];
			else if (statusIconFiles[status]!=string.Empty)
			{
				try
				{
					Icon icon = new Icon("icons\\" + statusIconFiles[status], new Size(16, 16));
					statusBitmap = icon.ToBitmap();
					statusIconBitmaps[status] = statusBitmap;
				}
				catch { }
			}
			if (statusBitmap != null)
			{
				for (int x = 0; x < 16; x++)
				{
					for (int y = 0; y < 16; y++)
					{
						Color sp = statusBitmap.GetPixel(x, y);
						if (sp.A != 0 || sp.R != 0 || sp.G != 0 || sp.B != 0)
						{
							fileBitmap.SetPixel(x, y, sp);
						}
					}
				}
			}
			FileIconsImageList.Images.Add(key, fileBitmap);
			return key;
		}

		public void AddLtfStatusToImage(string newImageName, Image image, LizardOverLayStatus status)
		{
			if (FileIconsImageList.Images.ContainsKey(newImageName))
				return;

			Bitmap fileBitmap = new Bitmap(image);
			Bitmap statusBitmap = null;
			if (statusIconBitmaps.ContainsKey(status))
				statusBitmap = statusIconBitmaps[status];
			else if (statusIconFiles[status] != string.Empty)
			{
				Icon icon = new Icon("icons\\" + statusIconFiles[status], new Size(16, 16));
				statusBitmap = icon.ToBitmap();
				statusIconBitmaps[status] = statusBitmap;
			}
			if (statusBitmap != null)
			{
				for (int x = 0; x < 16; x++)
				{
					for (int y = 0; y < 16; y++)
					{
						Color sp = statusBitmap.GetPixel(x, y);
						if (sp.A != 0 || sp.R != 0 || sp.G != 0 || sp.B != 0)
						{
							fileBitmap.SetPixel(x, y, sp);
						}
					}
				}
			}
			FileIconsImageList.Images.Add(newImageName, fileBitmap);
			return;
		}


		public static System.Drawing.Icon GetFileIcon(string name)
		{
			SHFILEINFO shfi = new SHFILEINFO();
			uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES;



			/* Check the size specified for return. */
			flags += Shell32.SHGFI_SMALLICON; // include the small icon flag

			SHGetFileInfo(name,
					Shell32.FILE_ATTRIBUTE_NORMAL,
					ref shfi,
					(uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi),
					flags);


			// Copy (clone) the returned icon to a new object, thus allowing us 
			// to call DestroyIcon immediately
			System.Drawing.Icon icon = (System.Drawing.Icon)
													 System.Drawing.Icon.FromHandle(shfi.hIcon).Clone();
			User32.DestroyIcon(shfi.hIcon); // Cleanup
			return icon;
		}

		public Bitmap LoadIconFileAsSmallBitmap(string iconFilename)
		{
			Icon icon = new Icon(iconFilename, new Size(16,16));
			Bitmap bm = icon.ToBitmap();
			return bm;
		}
	}

	public class Shell32
	{

		public const int MAX_PATH = 256;
		[StructLayout(LayoutKind.Sequential)]
		public struct SHITEMID
		{
			public ushort cb;
			[MarshalAs(UnmanagedType.LPArray)]
			public byte[] abID;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct ITEMIDLIST
		{
			public SHITEMID mkid;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct BROWSEINFO
		{
			public IntPtr hwndOwner;
			public IntPtr pidlRoot;
			public IntPtr pszDisplayName;
			[MarshalAs(UnmanagedType.LPTStr)]
			public string lpszTitle;
			public uint ulFlags;
			public IntPtr lpfn;
			public int lParam;
			public IntPtr iImage;
		}

		// Browsing for directory.
		public const uint BIF_RETURNONLYFSDIRS = 0x0001;
		public const uint BIF_DONTGOBELOWDOMAIN = 0x0002;
		public const uint BIF_STATUSTEXT = 0x0004;
		public const uint BIF_RETURNFSANCESTORS = 0x0008;
		public const uint BIF_EDITBOX = 0x0010;
		public const uint BIF_VALIDATE = 0x0020;
		public const uint BIF_NEWDIALOGSTYLE = 0x0040;
		public const uint BIF_USENEWUI = (BIF_NEWDIALOGSTYLE | BIF_EDITBOX);
		public const uint BIF_BROWSEINCLUDEURLS = 0x0080;
		public const uint BIF_BROWSEFORCOMPUTER = 0x1000;
		public const uint BIF_BROWSEFORPRINTER = 0x2000;
		public const uint BIF_BROWSEINCLUDEFILES = 0x4000;
		public const uint BIF_SHAREABLE = 0x8000;

		[StructLayout(LayoutKind.Sequential)]
		public struct SHFILEINFO
		{
			public const int NAMESIZE = 80;
			public IntPtr hIcon;
			public int iIcon;
			public uint dwAttributes;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
			public string szDisplayName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)]
			public string szTypeName;
		};

		public const uint SHGFI_ICON = 0x000000100;     // get icon
		public const uint SHGFI_DISPLAYNAME = 0x000000200;     // get display name
		public const uint SHGFI_TYPENAME = 0x000000400;     // get type name
		public const uint SHGFI_ATTRIBUTES = 0x000000800;     // get attributes
		public const uint SHGFI_ICONLOCATION = 0x000001000;     // get icon location
		public const uint SHGFI_EXETYPE = 0x000002000;     // return exe type
		public const uint SHGFI_SYSICONINDEX = 0x000004000;     // get system icon index
		public const uint SHGFI_LINKOVERLAY = 0x000008000;     // put a link overlay on icon
		public const uint SHGFI_SELECTED = 0x000010000;     // show icon in selected state
		public const uint SHGFI_ATTR_SPECIFIED = 0x000020000;     // get only specified attributes
		public const uint SHGFI_LARGEICON = 0x000000000;     // get large icon
		public const uint SHGFI_SMALLICON = 0x000000001;     // get small icon
		public const uint SHGFI_OPENICON = 0x000000002;     // get open icon
		public const uint SHGFI_SHELLICONSIZE = 0x000000004;     // get shell size icon
		public const uint SHGFI_PIDL = 0x000000008;     // pszPath is a pidl
		public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;     // use passed dwFileAttribute
		public const uint SHGFI_ADDOVERLAYS = 0x000000020;     // apply the appropriate overlays
		public const uint SHGFI_OVERLAYINDEX = 0x000000040;     // Get the index of the overlay

		public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
		public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;

		[DllImport("Shell32.dll")]
		public static extern IntPtr SHGetFileInfo(
			string pszPath,
			uint dwFileAttributes,
			ref SHFILEINFO psfi,
			uint cbFileInfo,
			uint uFlags
			);
	}

	/// <summary>
	/// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example.
	/// </summary>
	public class User32
	{
		/// <summary>
		/// Provides access to function required to delete handle. This method is used internally
		/// and is not required to be called separately.
		/// </summary>
		/// <param name="hIcon">Pointer to icon handle.</param>
		/// <returns>N/A</returns>
		[DllImport("User32.dll")]
		public static extern int DestroyIcon(IntPtr hIcon);
	}
	[StructLayout(LayoutKind.Sequential)]
	public struct SHFILEINFO
	{
		public const int NAMESIZE = 80;
		public IntPtr hIcon;
		public int iIcon;
		public uint dwAttributes;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Shell32.MAX_PATH)]
		public string szDisplayName;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)]
		public string szTypeName;
	};

}
